<?php

/*

URIResolver for Desktopd
Copyright (C) 2015  Desktopd Developer(s)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

https://www.gnu.org/licenses/agpl.html

*/


namespace Desktopd\URIResolver;


/*
    NOTE: Modified for Desktopd!
    Future versions do not need to follow upstream development.
    (It is OK to completely drop the original code)
    
    This modification as whole is under GNU AGPL version 3 or later
    but the original copyright notice must be preserved!
    
    Original license is below:
*/


/**
 * A php library for converting relative urls to absolute.
 * Website: https://github.com/monkeysuffrage/phpuri
 *
 * <pre>
 * echo phpUri::parse('https://www.google.com/')->join('foo');
 * //==> https://www.google.com/foo
 * </pre>
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @author P Guardiario <pguardiario@gmail.com>
 * @version 1.0
 */


/**
    Usage of this version
    <?php
    
    namespace Desktopd\URIResolver;
    
    echo (new URIResolver('https://en.wikipedia.org/wiki/Main_Page'))
        ->resolve('/w/index.php?action=edit&title=Main_Page');
    
    // result: https://en.wikipedia.org/w/index.php?action=edit&title=Main_Page
*/


/**
 * phpUri
 */

class URIResolver {
    /**
     * http(s)://
     * @var string
     */
    protected $scheme;
    
    /**
     * www.example.com
     * @var string
     */
    protected $host;
    
    /**
     * /search
     * @var string
     */
    protected $path;
    
    /**
     * ?q=foo
     * @var string
     */
    protected $query;
    
    /**
     * #bar
     * @var string
     */
    protected $fragment;
    
    
    public function __construct ($string) {
        preg_match_all('/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/', $string, $m);
        $this->scheme = $m[2][0];
        $this->host = $m[4][0];
        $this->path = (empty($m[5][0]))?'/':$m[5][0];
        $this->query = $m[7][0];
        $this->fragment = $m[9][0];
    }
    
    private function normalizePath ($path) {
        if (empty($path)) {
            return '';
        }
        
        $normalized_path = $path;
        $normalized_path = preg_replace('`//+`', '/' , $normalized_path, -1, $c0);
        $normalized_path = preg_replace('`^/\\.\\.?/`', '/' , $normalized_path, -1, $c1);
        $normalized_path = preg_replace('`/\\.(/|$)`', '/' , $normalized_path, -1, $c2);
        $normalized_path = preg_replace('`/[^/]*?/\\.\\.(/|$)`', '/' , $normalized_path, -1, $c3);
        $num_matches = $c0 + $c1 + $c2 + $c3;
        
        return ($num_matches > 0) ? $this->normalizePath($normalized_path) : $normalized_path;
    }
    
    /**
     * Join with a relative url
     * @param string $relative the relative url to join
     * @return string
     */
    public function resolve ($relative) {
        $uri = new self($relative);
        
        switch (true) {
            case !empty($uri->scheme):
                break;
            
            case !empty($uri->host):
                break;
            
            case empty($uri->path):
                $uri->path = $this->path;
                
                if (empty($uri->query)) {
                    $uri->query = $this->query;
                }
                
                break;
            
            case strpos($uri->path, '/') === 0:
                break;
            
            default:
                $base_path = $this->path;
                
                if (strpos($base_path, '/') === false) {
                    $base_path = '';
                } else {
                    $base_path = preg_replace ('/\/[^\/]+$/' ,'/' , $base_path);
                }
                
                if (empty($base_path) && empty($this->host)) {
                    $base_path = '/';
                }
                
                $uri->path = $base_path . $uri->path;
                
                break;
            
        }
        
        if (empty($uri->scheme)) {
            $uri->scheme = $this->scheme;
            if (empty($uri->host)) {
                $uri->host = $this->host;
            }
        }
        
        return "$uri";
    }
    
    public function __toString () {
        $ret = "";
        if (!empty($this->scheme)) $ret .= "{$this->scheme}:";
        if (!empty($this->host)) $ret .= "//{$this->host}";
        $ret .= $this->normalizePath($this->path);
        if (!empty($this->query)) $ret .= "?{$this->query}";
        if (!empty($this->fragment)) $ret .= "#{$this->fragment}";
        return $ret;
    }
    
    public function __get ($name) {
        return isset($this->{$name}) ? $this->{$name} : null;
    }

}


// vim: ts=4 et ai

